-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MRG/ENH: apply_inverse_cov #6262
Conversation
This pull request introduces 2 alerts when merging 9eced1e into 3cc76b9 - view on LGTM.com new alerts:
Comment posted by LGTM.com |
Codecov Report
@@ Coverage Diff @@
## master #6262 +/- ##
==========================================
- Coverage 89.99% 85.57% -4.43%
==========================================
Files 453 453
Lines 82020 82100 +80
Branches 13000 13002 +2
==========================================
- Hits 73812 70254 -3558
- Misses 5381 9177 +3796
+ Partials 2827 2669 -158 |
Cool stuff @dengemann! I've looked into how to combine the XYZ and your original was correct, except that when doing Another change I made to the example is to also compute the power for the baseline period. Then, we can plot the power relative to baseline, which looks much cleaner. |
@larsoner @britta-wstnr @wmvanvliet @dengemann |
just that
… On 29 Nov 2019, at 17:42, Luke Bloy ***@***.***> wrote:
@larsoner @britta-wstnr @wmvanvliet @dengemann
Apart from restructuring and testing what needs to be done here?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
e403b04
to
78f624e
Compare
@larsoner @britta-wstnr @wmvanvliet @dengemann |
A good one is to source localize with MNE and compute the covariance of the sources and retain the diagonal.
The result is identical if all is done correctly. It may depend however on the solver settings. I can tell you though that it works with this code.
You get the idea?
… On 30 Dec 2019, at 16:14, Luke Bloy ***@***.***> wrote:
@larsoner @britta-wstnr @wmvanvliet @dengemann
Any opinions on testing? I could add a simple regression test or is there a 3rd party method/implementation we'd like to test against.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
@larsoner @britta-wstnr @wmvanvliet @dengemann A couple of potential issues remain and need to be discussed.
|
29418d0
to
330b8d3
Compare
This is ready for a final review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bloyl if you could add more explanations to both examples eg by making sure you have titles on stc plot always and that you have a short explanation to explain what this figures show. Thx
mne/minimum_norm/inverse.py
Outdated
# always combine vector components | ||
if is_free_ori: | ||
logger.info(' Combining the current components...') | ||
sol = sol[0::3] + sol[1::3] + sol[2::3] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So what happens when the user specifies pick_ori='vector'
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I don't understand your question. If pick_ori='vector'
then _is_free_ori
is True
and you combine the outputs from the inverse.
What happens with fixed orientation inverse operators is unfortunately not tested since you can only use pick_ori=None
with those and I don't have a comparable call to apply_inverse_raw
that will facilitate testing. Presumably, this would be the same as using pick_ori='normal'
and a suitably configured inverse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But pick_ori='vector'
should produce a VectorSourceEstimate
. We explicitly not support it in the apply_lcmv_cov
and apply_dics_cov
functions, as it should return vectors pointing in the direction of maximum power and we haven't gotten around to implementing that yet.
Im fine with disallowing it, my personal position is all the apply_inverse*
methods should return vectors and the pick_ori functionality put in the
source estimate objects. But that's another discussion.
I will say that it would have been helpful to have this api conversation 3
months ago when I took over the pr and asked what restructuring needed to
be done.
…On Wed, Feb 19, 2020, 4:33 AM Marijn van Vliet ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In mne/minimum_norm/inverse.py
<#6262 (comment)>:
> + logger.info(' Picked %d channels from the data' % len(sel))
+ logger.info(' Computing inverse...')
+
+ K, noise_norm, vertno, source_nn = _assemble_kernel(inv, label, method,
+ pick_ori)
+
+ # apply imaging kernel
+ sol = np.einsum('ij,ij->i', K, (cov.data[sel][:, sel] @ K.T).T)[:, None]
+
+ is_free_ori = (inverse_operator['source_ori'] ==
+ FIFF.FIFFV_MNE_FREE_ORI and pick_ori != 'normal')
+
+ # always combine vector components
+ if is_free_ori:
+ logger.info(' Combining the current components...')
+ sol = sol[0::3] + sol[1::3] + sol[2::3]
But pick_ori='vector' should produce a VectorSourceEstimate. We
explicitly not support it in the apply_lcmv_cov and apply_dics_cov
functions, as it should return vectors pointing in the direction of maximum
power and we haven't gotten around to implementing that yet.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#6262?email_source=notifications&email_token=ABKTXHIA52HP5IWZTNGZZMDRDT4IPA5CNFSM4HKEEJT2YY3PNVWWK3TUL52HS4DFWFIHK3DMKJSXC5LFON2FEZLWNFSXPKTDN5WW2ZLOORPWSZGOCWB4XYA#discussion_r381172467>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABKTXHN77RQIGSLBL3MIKGTRDT4IPANCNFSM4HKEEJTQ>
.
|
Let me know once I should take a look / help. |
If you want me to look into the |
The main thing that needs to be decided is the api. @wmvanvliet has reasonably raised 2 questions:
Once those are decided they are minimal changes needed to the method, but the test will need to be reworked depending on the decisions. |
I think 1 could be ok, although I'm not feeling very strongly about it. 2 is also a point that is somewhat confusing to me, I'd rather not support it at this point. Think that we have a power estimate here! |
I agree with @wmvanvliet that what you get out of |
dcaf730
to
a1ce007
Compare
Rebased, added support for The only remaining issue I see is the tolerance on the cov calc is not great, but that I think will be solved by #7369, let's try to get that in first, rebase this, and try again. |
21a4aba
to
1654b78
Compare
@wmvanvliet feel free to take a look now, other than the |
sol = cov.data[sel][:, sel] @ K.T | ||
sol = np.sum(K * sol.T, axis=1, keepdims=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this is not equivalent to
np.diag(K @ cov.data[sel][:, sel] @ K.T)
Which i think is what we want. Doesn't the current code include off-diagonal elements for the src covariance matrix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this is not equivalent to ...
It should be equivalent, though admittedly it is confusing because it looks like it might be computing something different. The diagonal entries of A @ B
are given by (A * B.T).sum(axis=1)
, i.e., the sum of the first-row-of-A-times-first-col-of-B, sum of second-row-of-A-times-second-col-of-B, etc. Just to check it numerically, this code works fine locally if I add it:
sol = np.sum(K * sol.T, axis=1, keepdims=True)
sol2 = np.diag(K @ cov.data[sel][:, sel] @ K.T)[:, np.newaxis]
sol3 = np.sum((K @ cov.data[sel][:, sel]) * K, axis=1, keepdims=True)
np.testing.assert_allclose(sol, sol2)
np.testing.assert_allclose(sol, sol3)
Doesn't the current code include off-diagonal elements for the src covariance matrix?
Nope, just the diagonal. The end result is has shape (n_src, 1)
.
04acb81
to
a80c7c3
Compare
00d2b84
to
2ef5eaf
Compare
... based on what @wmvanvliet said above:
I think it makes the most sense just not to allow Good to go for you in that case @bloyl ? |
Going from the CSD to the max-power orientation is computing the largest eigenvector of the matrix. You can see how it is done in the beamformer code when |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am late to the party here, apologies. I added some small comments regarding the examples.
Regarding the almost philosophical discussion about vector solutions and power estimates: to me it makes sense to have one power estimate per source orientation in that case and I have used those before (mostly for checking data/forward models). That's my 2 cents.
then let's do:
Here we will use dSPM as well as DICS and LCMV beamformers.
… |
ok !
… |
LCMV beamformer | ||
Linearly constrained minimum variance beamformer, which attempts to | ||
estimate activity for a given source while suppressing cross-talk from | ||
other regions, see :func:`mne.beamformer.make_lcmv`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@britta-wstnr @agramfort thanks for the comments, pushed a commit to address them. In the example I linked to :term:
s instead of giving the definitions there, which caused me to add LCMV
and DICS
to our glossary.rst
. @britta-wstnr can you just check to see if this is okay? If it's not, let me know how to modify it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@britta-wstnr I'll merge this once CIs come back happy, but feel free to open a PR to correct the wording
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@larsoner, thanks it is on my list to look at the glossary also with the beamformer tutorial I am writing!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI @britta-wstnr if you can get to the tutorial in the next couple of weeks it can make it into 0.20!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will do all I can! It has been on my to do list for way too long already anyway 🙈 ... the workload has been high the last couple months.
* mne power example * Fix combining xyz, compute power relative to baseline * mv method to min_norm folder * Fix Doc strings - us dB instead of log * Add second comparitive example * Better description * Ref other example * WIP: failing test * Test passes of ori-normal fails for others * fix example cleanup test * Fix testing * rebase * disallow pick_ori=vector and rework test * restructure test * FIX: Marijn comments * ENH: Simplify by routing through Evoked * FIX: Fix examples * FIX: decim * DOC: Comment [ci skip] * FIX: Remove cruft * FIX: Fix after rebase * FIX: Remove vector * DOC: Better docs * DOC: Document another [ci skip] * FIX: Remove workaround Co-authored-by: Marijn van Vliet <[email protected]> Co-authored-by: Luke Bloy <[email protected]> Co-authored-by: Eric Larson <[email protected]>
* mne power example * Fix combining xyz, compute power relative to baseline * mv method to min_norm folder * Fix Doc strings - us dB instead of log * Add second comparitive example * Better description * Ref other example * WIP: failing test * Test passes of ori-normal fails for others * fix example cleanup test * Fix testing * rebase * disallow pick_ori=vector and rework test * restructure test * FIX: Marijn comments * ENH: Simplify by routing through Evoked * FIX: Fix examples * FIX: decim * DOC: Comment [ci skip] * FIX: Remove cruft * FIX: Fix after rebase * FIX: Remove vector * DOC: Better docs * DOC: Document another [ci skip] * FIX: Remove workaround Co-authored-by: Marijn van Vliet <[email protected]> Co-authored-by: Luke Bloy <[email protected]> Co-authored-by: Eric Larson <[email protected]>
Here we go: a candidate for a future
apply_inverse_cov
function that gets us source power by projecting the data covariance.Feel free to edit!
cc @larsoner @britta-wstnr @wmvanvliet